package org.aceor.mddal.client.jdbc;

import org.aceor.mddal.client.jdbc.adapter.AbstractStatementAdapter;
import org.aceor.mddal.common.monitor.Monitor;
import org.aceor.mddal.common.monitor.MonitorPoint;
import org.aceor.mddal.common.sqlparser.result.SQLParsedResult;
import org.aceor.mddal.gateway.executor.ExecuteContext;
import org.aceor.mddal.gateway.executor.StatementExecutor;
import org.aceor.mddal.gateway.router.RealSqlContext;
import org.aceor.mddal.gateway.router.Router;
import org.aceor.mddal.gateway.sqlparser.SQLParserFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.List;
import java.util.Map;

/**
 * Created by lxue on 16/4/5.
 */
public class StatementFacade extends AbstractStatementAdapter implements Statement {

    private static final Logger log = LoggerFactory.getLogger(StatementFacade.class);

    private final DataSourceFacade dataSourceFacade;
    private final ConnectionFacade connectionFacade;

    public StatementFacade(DataSourceFacade dataSourceFacade, ConnectionFacade connectionFacade) {
        this.dataSourceFacade = dataSourceFacade;
        this.connectionFacade = connectionFacade;
    }

    @Override
    public ResultSet executeQuery(String sql) throws SQLException {
        List<ResultSet> resultSetList = createStatementExecutor(sql).executeQuery();
        return null;
    }

    @Override
    public int executeUpdate(String sql) throws SQLException {
        return createStatementExecutor(sql).executeUpdate();
    }

    @Override
    public boolean execute(String sql) throws SQLException {
        return createStatementExecutor(sql).execute();
    }

    @Override
    public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException {
        return createStatementExecutor(sql).executeUpdate(autoGeneratedKeys);
    }

    @Override
    public int executeUpdate(String sql, int[] columnIndexes) throws SQLException {
        return createStatementExecutor(sql).executeUpdate(columnIndexes);
    }

    @Override
    public int executeUpdate(String sql, String[] columnNames) throws SQLException {
        return createStatementExecutor(sql).executeUpdate(columnNames);
    }

    @Override
    public boolean execute(String sql, int autoGeneratedKeys) throws SQLException {
        return createStatementExecutor(sql).execute(autoGeneratedKeys);
    }

    @Override
    public boolean execute(String sql, int[] columnIndexes) throws SQLException {
        return createStatementExecutor(sql).execute(columnIndexes);
    }

    @Override
    public boolean execute(String sql, String[] columnNames) throws SQLException {
        return createStatementExecutor(sql).execute(columnNames);
    }

    private StatementExecutor createStatementExecutor(final String sql) throws SQLException {
        StatementExecutor stmtExecutor = new StatementExecutor();
        Router router = Router.getInstance(dataSourceFacade.getLogicTable());

        /**
         * sql 根据分库
         */
        SQLParsedResult sqlParsedResult = null;
        try {
            Monitor.startSqlParseMonitor(sql);
            sqlParsedResult = SQLParserFactory.createSQLParserEngine(sql, null, router.getAllTableShardingColumnsMapping()).parse();
            log.info("Sql :{}\nParse Result :{}", sql, sqlParsedResult);
        } finally {
            Monitor.stop(MonitorPoint.PARSE_SQL);
        }
        ExecuteContext executeContext = router.route(sqlParsedResult, sql, null);
        for (Map.Entry<String, List<RealSqlContext>> entry : executeContext.sqlMap.entrySet()) {
            Statement statement = connectionFacade.getConnection(entry.getKey()).createStatement();
            for (RealSqlContext realSqlContext : entry.getValue()) {
                stmtExecutor.addStatement(realSqlContext.sql, statement);
            }
        }
        return stmtExecutor;
    }
}
